Oops. Forgot bcr.c
authorrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Wed, 29 Jun 2005 18:48:54 +0000 (18:48 +0000)
committerrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Wed, 29 Jun 2005 18:48:54 +0000 (18:48 +0000)
gpsbabel/bcr.c [new file with mode: 0644]

diff --git a/gpsbabel/bcr.c b/gpsbabel/bcr.c
new file mode 100644 (file)
index 0000000..06ba79c
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+
+    Support for Motorrad Routenplaner (Map&Guide) .bcr files.
+
+    Copyright (C) 2005 Olaf Klein, o.b.klein@t-online.de
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+*/
+
+
+#include "defs.h"
+#include "garmin_tables.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+#define MYNAME "bcr"
+
+#define BCR_DEBUG
+// #undef  BCR_DEBUG
+    
+#define SEC_UNKNOWN    0
+#define SEC_CLIENT     1
+#define SEC_ROUTE      2
+#define SEC_DESCR      3
+#define SEC_COORD      4
+
+#define R_EARTH                6371000         /* radius of our big blue ball */
+
+/*  
+    6371014 would be a better value when converting to f.e. to mapsoure,
+    but this seems to be used by Map&Guide when exporting to XML. 
+*/
+
+static FILE *fin, *fout;
+char *filename;
+int curr_rte_num, target_rte_num;
+static double radius;
+
+/* placeholders for options */
+
+static char *rtenum_opt;
+static char *rtename_opt;
+static char *radius_opt;
+
+static
+arglist_t bcr_args[] = {
+       {"index", &rtenum_opt, "Index of route to write (if more the one in source)", NULL, ARGTYPE_INT },
+       {"name", &rtename_opt, "New name for the route", NULL, ARGTYPE_STRING },
+       {"radius", &radius_opt, "Radius of our big earth (default 6371000 meters)", NULL, ARGTYPE_FLOAT },
+       {0, 0, 0, 0, 0}
+};
+
+void
+bcr_init_radius(void)
+{
+       if (radius_opt != NULL)                         /* preinitialize the earth radius */
+       {
+           radius = atof(radius_opt);
+           if (radius < 0)
+               fatal(MYNAME ": Sorry, the radius should be greater than zero!\n");
+       }
+       else
+           radius = (double)R_EARTH;
+
+       if (global_opts.verbose_status > 0)
+           printf(MYNAME ": We calculate with radius %f meters.\n", radius);
+}
+
+static void
+bcr_rd_init(const char *fname)
+{
+       filename = xstrdup(fname);
+       fin = xfopen(fname, "r", MYNAME);
+       bcr_init_radius();
+}
+
+static void
+bcr_rd_deinit(void)
+{
+       fclose(fin);
+       xfree(filename);
+}
+
+/* ------------------------------------------------------------*/
+
+char *
+bcr_next_char(const char *buff)
+{
+       char *result = (char *)buff;
+       while (*result > '\0' && *result <= ' ') result++;      /* trim leading spaces */
+       return result;
+}
+
+waypoint *
+bcr_find_waypt(const char *name, route_head *route)            /* find a waypt by name, create new */
+{                                                              /* if not found */
+       waypoint *wpt;
+       queue *elem, *tmp;
+       
+       QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) 
+       {
+           wpt = (waypoint *) elem;
+           if (0 == strcmp(wpt->shortname, name)) 
+               return wpt;
+       }
+       wpt = waypt_new();
+       wpt->shortname = xstrdup(name);
+
+       return wpt;
+}
+
+#ifndef UTF8_SUPPORT
+char *
+bcr_iso8859_1_to_utf8(const char *s)
+{
+       int len;
+       char *res;
+       unsigned char c;
+       char *src, *dst;
+
+       if (s == NULL) return NULL;
+
+       len = 0;
+       src = (char *)s;
+       while ('\0' != (c = *src++))
+       {
+           len++;
+           if (c & 0x80) len++;
+       }
+
+       src = (char *)s;
+       dst = res = (void *) xmalloc(len + 1);
+       while ('\0' != (c = *src++))
+       {
+           if (c & 0x80)
+           {
+               *dst++ = (0xc0 | (c >> 6));
+               *dst++ = (c & 0xbf);
+           }
+           else
+           {
+               *dst++ = c;
+           }
+       }
+       *dst = '\0';
+       return res;
+}
+#endif
+
+void
+bcr_create_waypts_from_route(route_head *route)
+{
+       waypoint *wpt;
+       queue *elem, *tmp;
+       
+       QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) 
+       {
+           wpt = waypt_dupe((waypoint *) elem);
+           waypt_add(wpt);
+       }
+}
+
+void
+bcr_wgs84_to_mercator(const double lat, const double lon, int *north, int *east)
+{
+       double N, E;
+       
+       N = log(tan(lat * M_PI / 360 + M_PI / 4)) * radius;
+       E = lon * radius * M_PI / (double)180;
+       
+       if (lat > 0) N += 0.500000000001;       /* we go from double to integer */
+       else N -= 0.500000000001;               /* it's time to round a little bit */
+       if (lon > 0) E += 0.500000000001;
+       else E -= 0.500000000001;
+       
+       *north = N;
+       *east = E;
+}
+
+void
+bcr_mercator_to_wgs84(const int north, const int east, double *lat, double *lon)               
+{
+       *lat = 2 * (atan(exp(north / radius)) - M_PI / 4) / M_PI * (double)180;
+       *lon = (double)east * (double)180 / (radius * M_PI);
+}
+
+static int
+bcr_sort_route_by_index_cb(const void *a, const void *b)
+{
+       const waypoint *wa = *(waypoint **)a;
+       const waypoint *wb = *(waypoint **)b;
+       return wa->centiseconds - wb->centiseconds;
+}
+
+route_head *
+bcr_sort_route_by_index(route_head *route)
+{
+       route_head *result;
+       queue *elem, *tmp;
+       waypoint **list;
+       waypoint *wpt;
+       int i;
+       int count = route->rte_waypt_ct;
+       
+       if (count == 0) return (route);                                 /* nothing to do */
+       
+       result = route_head_alloc();
+       result->rte_name = xstrdup(route->rte_name);
+       route_add_head(result);
+       
+       list = (waypoint **) xcalloc(route->rte_waypt_ct, sizeof(*list));
+       i = 0;
+       QUEUE_FOR_EACH((queue *)&route->waypoint_list, elem, tmp)
+       {
+           wpt = (waypoint *)elem;
+           list[i++] = wpt;
+       }
+       qsort(list, route->rte_waypt_ct, sizeof(*list), bcr_sort_route_by_index_cb);
+       for (i=0; i<count; i++)
+       {
+           wpt = list[i];
+           wpt->centiseconds = 0;                                      /* reset our index container */
+           route_add_wpt(result, waypt_dupe(wpt));
+           route_del_wpt(route, wpt);
+       }
+       
+       xfree(list);
+       route_del_head(route);
+       
+       return result;
+}
+
+/* ------------------------------------------------------------- */
+
+static void
+bcr_data_read(void)
+{
+       char buff[1024];
+       char *src;
+       int section = SEC_UNKNOWN;
+       char *c, *cx, *ctemp;
+       int index;
+       int mlat, mlon;         /* mercator data */
+       double xalt;
+       int line, skip;
+       
+       route_head *route;
+       waypoint *wpt;
+       
+       route = route_head_alloc();
+       route_add_head(route);
+       
+       line = skip = 0;
+       src = NULL;
+       
+       while (NULL != fgets(buff, sizeof(buff), fin))
+       {
+           line++;
+           
+           c = buff;                           /* trim the end of the buffer */
+           cx = c + strlen(c) - 1;
+           while ((cx > c) && (*cx <= ' '))
+           {
+               *cx = '\0';
+               cx--;
+           }
+           if (src != NULL) xfree(src);
+           
+#ifdef UTF8_SUPPORT
+           src = str_iso8859_1_to_utf8(buff);
+#else
+           src = bcr_iso8859_1_to_utf8(buff);  /* internal copy str_iso8859_1_to_utf8 */
+#endif
+           /* !! buff is now free and can be used */
+           
+           c = bcr_next_char(src);             /* skip spaces */
+           if (*c == '\0') continue;           /* skip empty lines */
+           
+           if (*c == '[')                      /* new section */
+           {
+               skip = 0;
+               
+               c = bcr_next_char(++c);
+               cx = strchr(c, ']');
+               if (cx == NULL) fatal(MYNAME ": error in file structure (\"]\" expected)!\n");
+               
+               *cx = '\0';
+               if (strcmp(c, "CLIENT") == 0) section = SEC_CLIENT;
+               else if (strcmp(c, "ROUTE") == 0) section = SEC_ROUTE;
+               else if (strcmp(c, "DESCRIPTION") == 0) section = SEC_DESCR;
+               else if (strcmp(c, "COORDINATES") == 0) section = SEC_COORD;
+               else 
+               {
+                   printf(MYNAME ": unknown section \"%s\".\n", c);
+                   skip = 1;
+               }
+               continue;
+           }
+           
+           if (skip != 0) continue;
+               
+           cx = strchr(c, '=');
+           if (cx == NULL) continue;
+           
+           *cx++ = '\0';                       /* delimit in key and data */
+
+           if ((section == SEC_CLIENT) && (strcmp(c, "ROUTENAME") == 0))
+           {
+               route->rte_name = xstrdup(cx);
+           }
+           else
+           {
+               if (strncmp(c, "STATION", 7) != 0) continue;
+               index = atoi(c+7);
+
+               /* bcr_find_waypt(... creates new waypoint, if not in queue */
+               
+               switch(section)
+               {
+                   case SEC_CLIENT:
+                       wpt = bcr_find_waypt(c, route);
+                       wpt->centiseconds = index;
+                       ctemp = strchr(cx, ',');
+                       if (ctemp != NULL) *ctemp = ' ';
+                       if (2 != sscanf(cx, "%s %lf", buff, &xalt))
+                           fatal(MYNAME ": structure error on line %d!\n(data: %s=%s)\n", line, c, cx);
+#if 0
+                       if (xalt != 999999999)
+                           wpt->altitude = xalt / 3.2808;      /* convert feet to meters */
+#endif
+                       route_add_wpt(route, wpt);
+                       
+                       if (case_ignore_strcmp(buff, "standort") == 0)
+                           wpt->icon_descr = mps_find_desc_from_icon_number(18, MAPSOURCE);
+                       else if (case_ignore_strcmp(buff, "Town") == 0)
+                           wpt->icon_descr = mps_find_desc_from_icon_number(69, MAPSOURCE);
+                       else
+                           printf(MYNAME ": Unknown icon \"%s\" found. Please report.\n", buff);
+                       break;
+
+                   case SEC_DESCR:
+                       wpt = bcr_find_waypt(c, route); 
+                       wpt->centiseconds = index;
+                       
+                       ctemp = strchr(cx, '@');
+                       if (ctemp != NULL)
+                       {
+                           *ctemp-- = '\0';
+                           if (*ctemp == ',') *ctemp = '\0';
+                       }
+                       wpt->description = xstrdup(cx);
+                       break;
+
+                   case SEC_COORD:
+                       wpt = bcr_find_waypt(c, route); 
+                       wpt->centiseconds = index;
+                       if (2 != sscanf(cx, "%d,%d", &mlon, &mlat))
+                           fatal(MYNAME ": structure error on line %d!\n", line);
+                           
+                       bcr_mercator_to_wgs84(mlat, mlon, &wpt->latitude, &wpt->longitude);
+                   case SEC_ROUTE:
+                       break;
+               }
+           }
+       }
+       if (src != NULL) xfree(src);
+       src = NULL;
+       
+       route = bcr_sort_route_by_index(route);
+       bcr_create_waypts_from_route(route);
+}
+
+/* %%% bcr write support %%% ----------------------------------- */
+
+static void
+bcr_wr_init(const char *fname)
+{
+       filename = xstrdup(fname);
+       fout = xfopen(fname, "w", MYNAME);
+       bcr_init_radius();
+}
+
+static void
+bcr_wr_deinit(void)
+{
+       fclose(fout);
+       xfree(filename);
+}
+
+static void 
+bcr_route_trailer(const route_head *rte)
+{
+}
+
+static void
+bcr_write_wpt(const waypoint *wpt)
+{
+}
+
+void bcr_write_line(FILE *fout, const char *key, int *index, const char *value)
+{
+       if (value == NULL)                              /* this is mostly used in the world of windows */
+       {                                               /* so we respectfully add a CR/LF on each line */
+           fprintf(fout, "%s\x0d\n", key);
+       }
+       else
+       {
+           if (index != NULL)
+               fprintf(fout, "%s%d=%s\x0d\n", key, *index, value);
+           else
+               fprintf(fout, "%s=%s\x0d\n", key, value);
+       }
+}
+
+static void 
+bcr_route_header(const route_head *route)
+{
+       queue *elem, *tmp;
+       waypoint *wpt;
+       char *c;
+       int i, icon, north, east, nmin, nmax, emin, emax;
+       char buff[128], symbol[32];
+       
+       curr_rte_num++;
+       if (curr_rte_num != target_rte_num) return;
+       
+       
+       bcr_write_line(fout, "[CLIENT]", NULL, NULL);                   /* client section */
+
+       bcr_write_line(fout, "REQUEST", NULL, "TRUE");
+       
+       c = route->rte_name;
+       if (rtename_opt != 0) c = rtename_opt;
+       if (c != NULL)
+           bcr_write_line(fout, "ROUTENAME", NULL, c);
+       else
+           bcr_write_line(fout, "ROUTENAME", NULL, "Route");
+
+       bcr_write_line(fout, "DESCRIPTIONLINES", NULL, "1");
+       bcr_write_line(fout, "DESCRIPTION1", NULL, "");
+       
+       i = 0;
+       QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) 
+       {
+           i++;
+           wpt = (waypoint *) elem;
+           
+           strncpy(symbol, "Standort", sizeof(symbol));
+           if (wpt->icon_descr != 0)
+           {
+               icon = mps_find_icon_number_from_desc(wpt->icon_descr, MAPSOURCE);
+               if ((icon >= 69) && (icon <= 72))
+                   strncpy(symbol, "Town", sizeof(symbol));
+           }
+           snprintf(buff, sizeof(buff), "%s,%s", symbol, "999999999");
+           bcr_write_line(fout, "STATION", &i, buff);
+       }
+           
+       bcr_write_line(fout, "[COORDINATES]", NULL, NULL);              /* coords section */
+       
+       nmin = emin = (1<<30);
+       emax = nmax = -nmin;
+       
+       i = 0;
+       QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) 
+       {
+           i++;
+           wpt = (waypoint *) elem;
+           
+           bcr_wgs84_to_mercator(wpt->latitude, wpt->longitude, &north, &east);
+           
+           if (north > nmax) nmax = north;
+           if (east > emax) emax = east;
+           if (north < nmin) nmin = north;
+           if (east < emin) emin = east;
+           
+           snprintf(buff, sizeof(buff), "%d,%d", east, north);
+           bcr_write_line(fout, "STATION", &i, buff);
+       }
+       
+       bcr_write_line(fout, "[DESCRIPTION]", NULL, NULL);              /* descr. section */
+       
+       i = 0;
+       QUEUE_FOR_EACH(&route->waypoint_list, elem, tmp) 
+       {
+           i++;
+           wpt = (waypoint *) elem;
+           c = wpt->description;
+           if (c == NULL) c = wpt->shortname;
+           bcr_write_line(fout, "STATION", &i, c);
+       }
+       
+       bcr_write_line(fout, "[ROUTE]", NULL, NULL);                    /* route section */
+
+       snprintf(buff, sizeof(buff), "%d,%d,%d,%d", emin, nmax, emax, nmin);
+       bcr_write_line(fout, "ROUTERECT", NULL, buff);
+       
+}
+
+static void
+bcr_data_write(void)
+{
+       
+       if (global_opts.objective == rtedata)
+       {
+           target_rte_num = 1;
+           
+           if (rtenum_opt != NULL)
+           {
+               target_rte_num = atoi(rtenum_opt);
+               if ((target_rte_num > route_count()) || (target_rte_num < 1))
+                   fatal(MYNAME ": invalid route number %d (1..%d))!\n", 
+                       target_rte_num, route_count());
+           }
+           curr_rte_num = 0;
+           route_disp_all(bcr_route_header, bcr_route_trailer, bcr_write_wpt);
+       }
+}
+
+ff_vecs_t bcr_vecs = {
+       ff_type_file,
+       { ff_cap_none, ff_cap_read || ff_cap_write, ff_cap_none },
+       bcr_rd_init,
+       bcr_wr_init,
+       bcr_rd_deinit,
+       bcr_wr_deinit,
+       bcr_data_read,
+       bcr_data_write,
+       NULL,
+       bcr_args
+};
+